/*
 * Copyright (c) 2019-2029, <a href="https://wwww.intellijboy.cn">https://wwww.intellijboy.cn</a> (liuburu@qq.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * <a href="https://www.apache.org/licenses/LICENSE-2.0">https://www.apache.org/licenses/LICENSE-2.0</a>
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package cn.intellijboy.gradle.plugin.task;

import cn.intellijboy.gradle.plugin.model.ConfigurationModel;
import cn.intellijboy.gradle.plugin.model.ConfigurationType;
import cn.intellijboy.gradle.plugin.model.GradleBuildModel;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.Getter;
import lombok.Setter;
import org.gradle.api.DefaultTask;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.diagnostics.internal.ConfigurationDetails;
import org.gradle.api.tasks.diagnostics.internal.ProjectDetails;
import org.gradle.api.tasks.options.Option;
import org.gradle.internal.serialization.Cached;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 抽象的依赖分析父类
 *
 * @author intellijboy
 * @since 1.0
 */
public class AbstractDependencyAnalyzeTask extends DefaultTask {

    // gradle日志对象
    protected final Logger LOGGER = Logging.getLogger(getClass());


    protected final Cached<GradleBuildModel> buildModelCache = Cached.of(this::calculateReportModel);

    private GradleBuildModel calculateReportModel() {
        List<ConfigurationDetails> buildConfigurationDetails = getProject().getBuildscript().getConfigurations().stream().map(ConfigurationDetails::of).collect(Collectors.toList());
        List<ConfigurationDetails> projectConfigurationDetails = getProject().getConfigurations().stream().map(ConfigurationDetails::of).collect(Collectors.toList());
        return new GradleBuildModel(ProjectDetails.of(getProject()), buildConfigurationDetails, projectConfigurationDetails);
    }


    @Setter
    @Getter
    @Input
    @Optional
    @Option(option = "configuration", description = "指定要分析的配置名称，多个用逗号分隔，如：compileClasspath,runtimeClasspath")
    private String configuration;

    @Setter
    @Getter
    @Input
    @Optional
    @Option(option = "output", description = "输出方式：console（控制台）或文件路径")
    private String output = "console";

    /**
     * json格式打印
     *
     * @param object 打印对象
     */
    protected void jsonLogPrint(Object object) {
        ObjectMapper objectMapper = JsonMapper.builder()
                .defaultPropertyInclusion(JsonInclude.Value.empty())
                .configure(SerializationFeature.INDENT_OUTPUT, true)    // 格式化输出
                .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)      // 禁用空对象失败
                .build();
        try {
            LOGGER.warn(objectMapper.writeValueAsString(object));
        } catch (JsonProcessingException e) {
            LOGGER.error("配置项列表序列化异常：" + e.getMessage(), e);
        }
    }

    protected @NotNull List<ConfigurationModel> initConfigurationModels() {
        GradleBuildModel gradleBuildModel = buildModelCache.get();
        List<ConfigurationModel> configList = new ArrayList<>();
        configList.addAll(initConfiguration(ConfigurationType.BUILD, gradleBuildModel.buildConfigurations()));
        configList.addAll(initConfiguration(ConfigurationType.PROJECT, gradleBuildModel.configurations()));
        return configList;
    }

    /**
     * 初始化配置模型列表
     *
     * @param configurationType    配置类型，用于设置所有配置模型的类型
     * @param configurationDetails 配置详情列表，包含具体的配置信息
     * @return ConfigurationModel列表，包含根据配置详情构建的配置模型
     */
    private List<ConfigurationModel> initConfiguration(ConfigurationType configurationType, List<ConfigurationDetails> configurationDetails) {
        List<ConfigurationModel> resultList = new ArrayList<>();
        for (ConfigurationDetails configuration : configurationDetails) {
            resultList.add(ConfigurationModel.builder()
                    .configurationType(configurationType)
                    .name(configuration.getName())
                    .description(configuration.getDescription())
                    .canBeResolved(configuration.isCanBeResolved())
                    .build());
        }
        return resultList;
    }


}
